#include "ctrl.h"
#include <stdio.h>
#include "stm32f1xx_hal.h"
#include "usart.h"
#include "log.h"
#include "FreeRTOS.h"
#include "task.h"
#include "air780e.h"

static const char *TAG = "ctrl";

/**
 * @brief ctrl_init
 * @note  -- 初始化控制和反馈脚
 * @param ctrl 控制结构体指针
 */
void ctrl_init(ctrl_t *ctrl)
{
    GPIO_InitTypeDef GPIO_InitStruct;                     /* 定义结构体 */
    GPIO_InitStruct.Pin = ctrl->ctrl_pin;                 /* 输出引脚 */
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;           /* 推挽输出 */
    GPIO_InitStruct.Pull = GPIO_PULLUP;                   /* 内部上拉 */
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;         /* 输出速度 */
    HAL_GPIO_Init(ctrl->ctrl_pin_port, &GPIO_InitStruct); /* 初始化该结构体 */

    GPIO_InitStruct.Pin = ctrl->lag_pin;                 /* 输出引脚 */
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;              /* 设置输入 */
    GPIO_InitStruct.Pull = GPIO_NOPULL;                  /* 浮空输入 */
    HAL_GPIO_Init(ctrl->lag_pin_port, &GPIO_InitStruct); /* 初始化该结构体 */
}

/**
 * @brief  Get the ctrl pin state object
 * @note   获取控制引脚的电平
 * @param  ctrl 控制结构体指针
 * @retval lag_pin-Value
 * @return true
 * @return false
 */
static bool get_ctrl_pin_state(ctrl_t *ctrl)
{
    /*返回读取控制的开关反馈*/
    return HAL_GPIO_ReadPin(ctrl->lag_pin_port, ctrl->lag_pin);
}

/**
 * @brief Set the ctrl pin output object
 * @note  -- 设置控制引脚的输出电平
 * @param ctrl 控制结构体指针
 * @param PinState 输出电平
 */
static void set_ctrl_pin_output(ctrl_t *ctrl, GPIO_PinState PinState)
{
    HAL_GPIO_WritePin(ctrl->ctrl_pin_port, ctrl->ctrl_pin, PinState);
}

/**
 * @brief threshold_lag_ctrl
 * @note  -- 阈值滞后反馈和温度异常警告
 * @param ctrl 控制结构体指针
 * @param dht_data 传入温湿度数据进行阈值滞后控制
 * @param threshold 传入阈值大小
 */
static void threshold_lag_ctrl(ctrl_t *ctrl, dht_t *dht_data, struct menu_threshold *threshold)
{
    if (dht_data->temp > (threshold->temp + HYSTERESIS)) // 温度异常
    {
        // 当前温度高于阈值加上滞后阈值
        ctrl->env_state = false; // 赋值环境状态
        // 设备在开启时，进行关闭操作
        if (get_ctrl_pin_state(ctrl) == ctrl_on)
        {
            set_ctrl_pin_output(ctrl, GPIO_PIN_SET); // 关闭操作
            send_warning_sms_app();                  // 发送温度异常短信警报
        }
        MY_LOGI(TAG, "env is abnormal! and ctrl is turn off!\r\n");
    }
    else if (dht_data->temp < (threshold->temp - HYSTERESIS)) // 温度正常
    {
        // 当前温度低于阈值减去滞后阈值
        ctrl->env_state = true; // 赋值环境状态
        MY_LOGI(TAG, "env is normal!\r\n");
    }
}

/**
 * @brief ctrl_device
 * @note  -- 设备控制开关
 * @param ctrl 控制结构体指针
 */
static void ctrl_device(ctrl_t *ctrl)
{
    MY_LOGI(TAG, "get_ctrl_pin_state -> %d\r\n", get_ctrl_pin_state(ctrl)); // 读取状态(反馈)
    if (ctrl->env_state == true)                                            // 环境状态正常
    {
        switch (ctrl->device_ctrl)
        {
        case 0:
            MY_LOGI(TAG, "start close device\r\n");
            set_ctrl_pin_output(ctrl, GPIO_PIN_SET);                                // 关闭设备--HIGH
            MY_LOGI(TAG, "get_ctrl_pin_state -> %d\r\n", get_ctrl_pin_state(ctrl)); // 读取状态(反馈，如果关闭了就给控制位255，避免一直进入)
            MY_LOGI(TAG, "clear ctrl bit -> 255\r\n");
            ctrl->device_ctrl = 255;
            // 发送操作反馈短信
            send_ctrl_option_sms_app(false);
            break;
        case 1:
            MY_LOGI(TAG, "start open device\r\n");
            set_ctrl_pin_output(ctrl, GPIO_PIN_RESET);                              // 开启设备--LOW(使用阈值控制函数进行开启 --> 如果当前温度大于警报阈值就不开启，并发送警报反馈短信，最后退出该函数)
            MY_LOGI(TAG, "get_ctrl_pin_state -> %d\r\n", get_ctrl_pin_state(ctrl)); // 读取状态(反馈，如果开启了就给控制位255，避免一直进入)
            MY_LOGI(TAG, "clear ctrl bit -> 255\r\n");
            ctrl->device_ctrl = 255;
            // 发送操作反馈短信
            send_ctrl_option_sms_app(true);
            break;
        default:
            break;
        }

        switch (ctrl->device_restart)
        {
        case 1:
            MY_LOGI(TAG, "restart device\r\n");
            set_ctrl_pin_output(ctrl, GPIO_PIN_SET);                                // 关闭设备--HIGH(使用阈值控制函数进行开启)
            MY_LOGI(TAG, "get_ctrl_pin_state -> %d\r\n", get_ctrl_pin_state(ctrl)); // 读取状态(反馈，如果开启了就给控制位255，避免一直进入)
            vTaskDelay(500);
            set_ctrl_pin_output(ctrl, GPIO_PIN_RESET);                              // 开启设备--LOW(使用阈值控制函数进行开启 --> 如果当前温度大于警报阈值就不开启，并发送警报反馈短信，最后退出该函数)
            MY_LOGI(TAG, "get_ctrl_pin_state -> %d\r\n", get_ctrl_pin_state(ctrl)); // 读取状态(反馈，如果开启了就给控制位255，避免一直进入)
            MY_LOGI(TAG, "clear restart bit -> 255\r\n");
            ctrl->device_restart = 255;
            //  发送操作反馈短信
            break;
        default:
            break;
        }
    }
    else // 环境状态异常
    {
        switch (ctrl->device_ctrl)
        {
        case 0:
            MY_LOGI(TAG, "env is abnormal! and ctrl is not operational!\r\n");
            MY_LOGI(TAG, "get_ctrl_pin_state -> %d\r\n", get_ctrl_pin_state(ctrl)); // 读取状态(反馈，如果关闭了就给控制位255，避免一直进入)
            MY_LOGI(TAG, "clear ctrl bit -> 255\r\n");
            ctrl->device_ctrl = 255;
            // 发送操作反馈短信
            send_abnormal_sms_app();
            break;
        case 1:
            MY_LOGI(TAG, "env is abnormal! and ctrl is not operational!\r\n");
            MY_LOGI(TAG, "get_ctrl_pin_state -> %d\r\n", get_ctrl_pin_state(ctrl)); // 读取状态(反馈，如果开启了就给控制位255，避免一直进入)
            MY_LOGI(TAG, "clear ctrl bit -> 255\r\n");
            ctrl->device_ctrl = 255;
            // 发送操作反馈短信
            send_abnormal_sms_app();
            break;
        default:
            break;
        }

        switch (ctrl->device_restart)
        {
        case 1:
            MY_LOGI(TAG, "restart device\r\n");
            MY_LOGI(TAG, "get_ctrl_pin_state -> %d\r\n", get_ctrl_pin_state(ctrl)); // 读取状态(反馈，如果开启了就给控制位255，避免一直进入)
            MY_LOGI(TAG, "clear restart bit -> 255\r\n");
            ctrl->device_restart = 255;
            //  发送操作反馈短信
            send_abnormal_sms_app();
            break;
        default:
            break;
        }
    }
}

/**
 * @brief ctrl_proc
 * @note  控制进程
 * @param ctrl 控制结构体指针
 * @param dht_data 传入温湿度数据进行阈值滞后控制
 * @param threshold 传入阈值大小
 */
void ctrl_proc(ctrl_t *ctrl, dht_t *dht_data, struct menu_threshold *threshold)
{
    threshold_lag_ctrl(ctrl, dht_data, threshold);
    ctrl_device(ctrl);
}
